import random

from re import match

import redis
from flask import current_app
from flask import request, jsonify
from flask import session

from info import constants, db
from info import redis_store
from info.models import User
from info.utils.captcha.captcha import captcha
from flask import make_response

# 创建蓝图
from info.modules.passport import passport_blu
from info.utils.response_code import RET
from info.utils.yuntongxun.sms import CCP


@passport_blu.route("/image_code")
def get_image_code():
    '''
    图片验证码：
    业务逻辑：
    1.获取用户输入信息，校验
    2.生成图片验证码
    3.保存图片验证码文本到redis
    4.返回图片验证码
    '''

    # 1.获取用户信息并校验
    image_code_id = request.args.get("image_code_id")

    if not image_code_id:
        return jsonify(errno=RET.NODATA, errmsg="没有数据")

    # 2.生成图片验证码
    name, text, content = captcha.generate_captcha()

    # 3.保存图片验证码的文本到redis
    try:
        # 用前面设置的redis_store对象（继承redis.StrictRedis）保存数据（uuid(键)，text（值），有效时间（从contants文件中找预设））;IMAGE_CODO_ 方便在redis查看
        redis_store.set("IMAGE_CODE_" + image_code_id, text, constants.IMAGE_CODE_REDIS_EXPIRES)
    except Exception as e:
        current_app.loggin.error(e)  # 记录日志
        return jsonify(errno=RET.DATAERR, errmsg="保存数据出错")

    # 4.返回图片验证码
    response = make_response(content)
    response.headers["Content-Type"] = "image/jpg"

    return response


@passport_blu.route("/sms_code", methods=["POST"])
def sms_code():
    '''
    短信验证码：
    业务逻辑：
    1.获取参数，判空(手机号，用户输入的图片验证码，image_code_id(uuid))
    2.对比redis的图片验证码文本(通过uuid获取)与用户输入的图片验证码文本是否相同
    3.发送短信验证码
    3.1　查询数据库中，用户是否存在
    3.2　生成随机验证码，发送
    3.3　保存短信验证码文本到redis中
    4.return返回给浏览器
    '''

    # 1.获取参数，判空(手机号，用户输入的图片验证码，image_code_id(uuid))
    params_dict = request.json  # 获取前端传来的字符，并转换为字典
    mobile = params_dict.get("mobile")
    image_code = params_dict.get("image_code")
    image_code_id = params_dict.get("image_code_id")
    # 判空
    if not all([mobile, image_code, image_code_id]):
        return jsonify(errno=RET.DATAERR, errmsg="参数错误")
    # 判断手机号是否合法
    if not match(r"^[1][345789][0-9]{9}$", mobile):
        return jsonify(errno=RET.DATAERR, errmsg="手机号不合法")

    # 2.对比redis的图片验证码文本(通过uuid获取)与用户输入的图片验证码文本是否相同
    try:
        real_image_code = redis_store.get("IMAGE_CODE_" + image_code_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DATAERR, errmsg="获取图片验证码失败")

    if not real_image_code:
        return jsonify(errno=RET.DATAERR, errmsg="参数错误")

        # 检测是否一致
    if real_image_code.decode().lower() != image_code.lower():
        return jsonify(errno=RET.DATAERR, errmsg="验证码错误")

        # 3.发送短信验证码
        # 3.1　查询数据库中，用户是否存在
    try:
        user = User.query.filter(User.mobile == mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DATAERR, errmsg="数据查询失败")

    if user:
        return jsonify(errno=RET.DATAERR, errmsg="用户已注册")

    # 3.2　生成随机验证码，发送
    ret = random.randint(0, 999999)
    sms_code = "%06d" % ret  # 6位，不够位数补0

    ccp = CCP()
    ccp.send_template_sms(mobile, [sms_code, constants.SMS_CODE_REDIS_EXPIRES // 60], 1)
    # 3.3　保存短信验证码文本到redis中
    try:
        # 用前面设置的redis_store对象（继承redis.StrictRedis）保存数据（uuid(键)，text（值），有效时间（从contants文件中找预设））;IMAGE_CODO_ 方便在redis查看
        redis_store.set("SMS_CODE_" + mobile, sms_code, constants.IMAGE_CODE_REDIS_EXPIRES)
    except Exception as e:
        current_app.loggin.error(e)  # 记录日志
        return jsonify(errno=RET.DATAERR, errmsg="保存数据出错")
    # 4.return返回给浏览器
    return jsonify(errno=RET.OK, errmsg="发送成功")


@passport_blu.route("/register", methods=["POST"])
def register():
    '''
    注册按钮
    业务逻辑：
    1.获取参数，判空
     2.对比，用户输入的短信验证码文本与redis保存的是否一致
     3.用户注册成功（给数据库对应（user）表，添加记录:创建User表对象，设置数据：db.session.add() commit()）
     4.保持登录（通过设置session）
     5.返回信息给浏览器
      '''

    # 1.获取参数，判空
    params_dict = request.json
    mobile = params_dict.get("mobile")
    sms_code = params_dict.get("sms_code")
    password = params_dict.get("password")
    agree = params_dict.get("agree")
    # 判空
    if not all([mobile, sms_code, password, agree]):
        return jsonify(errno=RET.DATAERR, errmsg="参数不全")

    # 2.对比，用户输入的短信验证码文本与redis保存的是否一致
    try:
        real_sms_code = redis_store.get("SMS_CODE_" + mobile)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="获取短信验证码失败")

    if not real_sms_code:
        return jsonify(errno=RET.NODATA, errmsg="短信验证码已经过期")

    if real_sms_code.decode() != sms_code:
        return jsonify(errno=RET.DATAERR, errmsg="输入的短信验证码错误")

    # 3.用户注册成功（给数据库对应（user）表，添加记录:创建User表对象，设置数据：db.session.add() commit()
    user = User()
    user.mobile = mobile  # 手机号
    user.nick_name = mobile  # 用户名(用户没修改，默认手机号)
    user.password = password  # 密码

    try:
        db.session.add(user)
        db.session.commit()
    except Exception as e:
        db.session.rollback()  # 事务回滚
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="数据库操作失败")

    # 4.保持登录（通过设置session）
    session["user_id"] = user.id
    session["mobile"] = user.mobile
    session["nick_name"] = user.nick_name

    # 5.返回信息给浏览器
    return jsonify(errno=RET.OK, errmsg="注册成功")


@passport_blu.route("/login", methods=["POST"])
def login():
    '''
    登录：
    业务逻辑：
    1.获取，判空
    2.查询验证手机号（用户名）是否存在
    3.验证密码
    4.保持登录状态（在sesion）
    5.返回登录成功
    '''
    # 1.获取，判空
    params_dict = request.json
    mobile = params_dict.get("mobile")
    password = params_dict.get("password")
    # 判空
    if not all([mobile, password]):
        return jsonify(errno=RET.DATAERR, errmsg="参数不全")

    # 2.查询验证手机号（用户名）是否存在
    try:
        user = User.query.filter(User.mobile == mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DATAERR, errmsg="数据查询失败")

    if not user:
        return jsonify(errno=RET.DATAERR, errmsg="该用户不存在")

    # 3.验证密码
    if not user.check_passowrd(password):
        return jsonify(errno=RET.DATAERR, errmsg="密码错误")

    # 记录最后一次的登录时间
    from datetime import datetime
    user.last_login = datetime.now()

    try:
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)  # 没必要return,因为没必要因为获取时间错误阻止用户登录

    # 4.保持登录状态（在sesion）
    session["user_id"] = user.id
    session["mobile"] = user.mobile
    session["nick_name"] = user.nick_name

    # 5.返回登录成功
    return jsonify(errno=RET.OK, errmsg="注册成功")


@passport_blu.route("/logout")
def logout():
    '''
    登出：（退出登录）
    1.手动删除session(方法:session.pop)
    2.返回信息给前端
    '''
    # 1.手动删除session
    session.pop("user_id")
    session.pop("mobile")
    session.pop("nick_name")

    # 2.返回信息给前端
    return jsonify(erron=RET.OK, errmsg="退出成功")
